#pragma once
#include <pthread.h>
#include <queue>
#include <unistd.h>
#include <iostream>

namespace ns_thread_pool
{
    const int default_num = 5;
    const int default_cap = 10;

    template <class T>
    class ThreadPool
    {
    private:
        std::queue<T> q;       //任务队列
        int _num;              //线程的数量
        int _cap;              //队列的容量
        pthread_cond_t cond;
        pthread_mutex_t mtx;

        static ThreadPool<T>* ins;   //单例
    private:
        void Wait()
        {
            pthread_cond_wait(&cond, &mtx);
        }   

        void WakeUp()
        {
            pthread_cond_signal(&cond);
        }

        void Lock()
        {
            pthread_mutex_lock(&mtx);
        }

        void Unlock()
        {
            pthread_mutex_unlock(&mtx);
        }

        bool IsEmpty()
        {
            return q.empty();
        }

        bool IsFull()
        {
            return q.size() == _cap;
        }

        ThreadPool(const int num = default_num, const int cap = default_cap) : _num(num), _cap(cap)
        {
            pthread_cond_init(&cond, nullptr);
            pthread_mutex_init(&mtx, nullptr);
        }

        ThreadPool<T>(const ThreadPool<T>& tp) = delete;
        ThreadPool<T>& operator=(ThreadPool<T>& tp) = delete; 
    public:
        static ThreadPool<T>* GetInstance()
        {
            static pthread_mutex_t mtx_1 = PTHREAD_MUTEX_INITIALIZER;
            if(nullptr == ins)
            {
                pthread_mutex_lock(&mtx_1);
                if(nullptr == ins)
                {
                    ins = new ThreadPool<T>();
                    ins->InitThreadPool();
                }
                pthread_mutex_unlock(&mtx_1);
            }

            return ins;
        }

        static void* thread_run(void* args)
        {
            pthread_detach(pthread_self());
            ThreadPool<T>* tp = (ThreadPool<T>*)args;
            while(true)
            {
                tp->Lock();
                while(tp->IsEmpty())
                {
                    tp->Wait();
                }
                T data;
                tp->pop(&data);
                //tp->WakeUp();
                std::cout << "消费者消费的数据是 " << data.d1 << data.op << data.d2 << "=" << data.run() << std::endl;
                tp->Unlock();
            }
        } 

        void InitThreadPool()
        {
            pthread_t tid;
            for(int i = 0;i < _num;++i)
            {
                pthread_create(&tid, nullptr, thread_run, (void*)this);
            }
        }

        void push(const T& in)
        {
            Lock();
            q.push(in);
            Unlock();
            WakeUp();
        }

        void pop(T* out)
        {
            *out = q.front();
            q.pop();
        }

        ~ThreadPool()
        {
            pthread_cond_destroy(&cond);
            pthread_mutex_destroy(&mtx);
        }
    };

    template <class T>
    ThreadPool<T>* ThreadPool<T>::ins = nullptr;
}